<!-- 文件选择器 -->
<template>
  <EleModal
    :width="988"
    :title="title"
    position="center"
    :zIndex="baseIndex"
    v-bind="modalProps || {}"
    v-model="visible"
    class="file-picker-modal"
    @open="handleOpen"
    @close="handleClose"
  >
    <EleSplitPanel
      ref="splitRef"
      space="0px"
      size="186px"
      :flexTable="true"
      :allowCollapse="mobile"
      :customStyle="{ borderWidth: '0 1px 0 0' }"
      class="file-picker-wrapper"
    >
      <FileGroup
        ref="fileGroupRef"
        :groupData="groupData"
        @groupSelect="handleGroupSelect"
        @addBtnClick="openGroupAdd()"
        @moreIconClick="openCtxMenuDropdown"
        @hideGroupCtxMenu="hideGroupContextmenu()"
      />
      <template #body>
        <FileList
          ref="fileListRef"
          :limit="limit"
          :fileLimit="fileLimit"
          :accept="accept"
          :params="params"
          :fileListProps="fileListProps"
          :selectionListProps="selectionListProps"
          :emptyProps="emptyProps"
          :paginationProps="paginationProps"
          :baseIndex="componentIndex"
          :messageIns="messageIns"
          @queryStart="showLoading"
          @queryDone="hideLoading"
          @renameFile="openRenameItem"
          @moveFile="openMoveItem"
          @removeFile="removeItem"
          @fileItemContextOpen="hideGroupContextmenu"
        />
      </template>
    </EleSplitPanel>
    <EleLoading :loading="loading" class="file-picker-loading" />
    <!-- 添加分组弹窗 -->
    <FileGroupAdd
      v-model="showGroupAdd"
      :parent_id="groupParentId"
      :groupData="groupData"
      :modalProps="groupAddModalProps"
      :baseIndex="componentIndex"
      :messageIns="messageIns"
      @done="handleReloadData"
    />
    <!-- 分组或文件重命名弹窗 -->
    <FileRename
      v-model="showRename"
      :data="renameData"
      :modalProps="renameModalProps"
      :baseIndex="componentIndex"
      :messageIns="messageIns"
      @done="handleReloadData"
    />
    <!-- 文件移动弹窗 -->
    <FileMove
      v-model="showMove"
      :data="moveData"
      :groupData="groupData"
      :modalProps="moveModalProps"
      :baseIndex="componentIndex"
      :messageIns="messageIns"
      @done="handleReloadData"
    />
    <!-- 分组项右键菜单 -->
    <EleDropdown
      :triggerKeys="[]"
      :persistent="false"
      :validateEvent="false"
      :zIndex="componentIndex"
      placement="bottom-end"
      :iconProps="{ size: 15 }"
      :popperOptions="{
        strategy: 'fixed',
        modifiers: [{ name: 'offset', options: { offset: [6, 6] } }],
      }"
      v-bind="groupDropdownProps || {}"
      ref="ctxMenuDropdownRef"
      trigger="click"
      componentType="pro"
      :preventContextmenu="true"
      :virtualTriggering="true"
      :virtualRef="ctxMenuDropdownVirtualRef"
      :items="ctxMenuDropdownItems"
      @command="handleItemCommand"
    />
    <!-- 消息提示容器 -->
    <div
      ref="messageWrapRef"
      class="ele-message-wrapper"
      :style="{ position: 'fixed', zIndex: messageIndex }"
    ></div>
    <div
      ref="messageBoxWrapRef"
      class="ele-message-box-wrapper"
      :style="{ position: 'fixed', zIndex: messageIndex }"
    ></div>
    <template #footer>
      <ElButton @click="handleCancel">取消</ElButton>
      <ElButton type="primary" @click="handleConfirm">确定</ElButton>
    </template>
  </EleModal>
</template>

<script setup>
import { ref, computed, nextTick, markRaw } from "vue";
import { useMessage, useMessageBox, toTree, findTree } from "ele-admin-plus/es";
import {
  EditOutlined,
  FolderOutlined,
  DeleteOutlined,
} from "@/components/icons";
import { useMobile } from "@/utils/use-mobile";
import FileGroup from "./components/file-group.vue";
import FileList from "./components/file-list.vue";
import FileGroupAdd from "./components/file-group-add.vue";
import FileRename from "./components/file-rename.vue";
import FileMove from "./components/file-move.vue";
import { listFiles, removeFile } from "@/api/system/file";

defineOptions({ name: "FilePicker" });

const props = defineProps({
  /** 标题 */
  title: {
    type: String,
    default: "文件选择",
  },
  /** 弹窗参数 */
  modalProps: Object,
  /** 最大选择数量 */
  limit: Number,
  /** 文件大小限制, 单位MB */
  fileLimit: {
    type: Number,
    default: 100,
  },
  /** 接受上传的文件类型 */
  accept: String,
  /** 接口查询参数 */
  params: Object,
  /** 分组下拉菜单属性 */
  groupDropdownProps: Object,
  /** 添加分组弹窗参数 */
  groupAddModalProps: Object,
  /** 重命名弹窗参数 */
  renameModalProps: Object,
  /** 移动分组弹窗参数 */
  moveModalProps: Object,
  /** 文件列表自定义属性 */
  fileListProps: Object,
  /** 已选列表自定义属性 */
  selectionListProps: Object,
  /** 空组件属性 */
  emptyProps: Object,
  /** 分页组件属性 */
  paginationProps: Object,
  /** 统一设置层级 */
  baseIndex: Number,
});

const emit = defineEmits(["done", "close"]);

/** 弹窗是否打开 */
const visible = defineModel({ type: Boolean });

/** 是否是移动端 */
const { mobile } = useMobile();

/** 分割面板组件 */
const splitRef = ref(null);

/** 文件分组组件 */
const fileGroupRef = ref(null);

/** 文件列表组件 */
const fileListRef = ref(null);

/** 数据请求状态 */
const loading = ref(false);

/** 分组数据 */
const groupData = ref([]);

/** 选中分组数据 */
const groupSelected = ref(null);

/** 是否显示重命名弹窗 */
const showRename = ref(false);

/** 当前重命名数据 */
const renameData = ref(null);

/** 是否显示添加分组弹窗 */
const showGroupAdd = ref(false);

/** 添加分组的上级分组id */
const groupParentId = ref();

/** 是否显示移动弹窗 */
const showMove = ref(false);

/** 当前移动数据 */
const moveData = ref(null);

/** 当前编辑是否是操作文件 */
const isEditFile = ref(false);

/** 右键菜单组件 */
const ctxMenuDropdownRef = ref();

/** 右键菜单虚拟触发节点 */
const ctxMenuDropdownVirtualRef = ref();

/** 右键菜单项数据 */
const ctxMenuDropdownItems = ref([]);

/** 当前打开的右键菜单对应的数据 */
let ctxMenuFileItem = null;

/** 组件统一层级 */
const componentIndex = computed(() => {
  if (props.baseIndex == null) {
    return;
  }
  return props.baseIndex + 100;
});

/** 消息提示组件层级 */
const messageIndex = computed(() => {
  if (componentIndex.value == null) {
    return 3000;
  }
  return componentIndex.value + 100;
});

/** 消息提示容器 */
const messageWrapRef = ref();

/** 消息弹出框容器 */
const messageBoxWrapRef = ref();

/** 消息提示框 */
const messageIns = useMessage({
  inner: true,
  appendTo: messageWrapRef,
});

/** 消息弹出框 */
const messageBoxIns = useMessageBox({
  appendTo: messageBoxWrapRef,
});

/** 获取分组右键菜单项数据 */
const getGroupCtxMenuItems = (_item) => {
  return [
    { title: "重命名", command: "rename", icon: markRaw(EditOutlined) },
    {
      title: "添加分组",
      command: "add",
      icon: markRaw(FolderOutlined),
      iconStyle: { transform: "scale(0.92)" },
    },
    {
      title: "删除分组",
      command: "remove",
      icon: markRaw(DeleteOutlined),
      divided: true,
      danger: true,
    },
  ];
};

/** 关闭分组右键菜单 */
const hideGroupContextmenu = () => {
  ctxMenuDropdownRef.value && ctxMenuDropdownRef.value.handleClose();
};

/** 打开分组右键菜单 */
const openCtxMenuDropdown = (triggerEl, item) => {
  ctxMenuFileItem = item;
  if (triggerEl == null || ctxMenuDropdownVirtualRef.value === triggerEl) {
    return;
  }
  hideGroupContextmenu();
  nextTick(() => {
    ctxMenuDropdownItems.value = getGroupCtxMenuItems(item) || [];
    ctxMenuDropdownVirtualRef.value = triggerEl;
    if (ctxMenuDropdownItems.value.length) {
      nextTick(() => {
        ctxMenuDropdownRef.value && ctxMenuDropdownRef.value.handleOpen();
      });
    }
  });
};

/** 分组选中 */
const handleGroupSelect = (item, isTreeClick) => {
  if (groupSelected.value != null && mobile.value) {
    splitRef.value?.toggleCollapse?.(true);
  }
  if (item && item.id != null) {
    if (!isTreeClick) {
      fileGroupRef.value?.setSelectedGroup?.(item);
    }
    if (groupSelected.value == null || groupSelected.value.id !== item.id) {
      groupSelected.value = item;
      queryData(item.id);
    }
  }
};

/** 编辑完成刷新数据事件 */
const handleReloadData = () => {
  isEditFile.value ? queryData() : queryGroup();
};

/** 添加分组 */
const openGroupAdd = (item) => {
  isEditFile.value = false;
  groupParentId.value = item ? item.id : void 0;
  showGroupAdd.value = true;
};

/** 重命名分组或文件 */
const openRenameItem = (item, isFile) => {
  isEditFile.value = !!isFile;
  renameData.value = item;
  showRename.value = true;
};

/** 文件移动到指定分组 */
const openMoveItem = (item, isFile) => {
  isEditFile.value = !!isFile;
  moveData.value = item;
  showMove.value = true;
};

/** 删除分组或文件 */
const removeItem = (item, isFile) => {
  isEditFile.value = !!isFile;
  messageBoxIns
    ?.confirm?.(`确定要删除“${item.name}”吗?`, "系统提示", {
      type: "warning",
      draggable: true,
    })
    ?.then?.(() => {
      const loading = messageIns?.loading?.({
        message: "请求中..",
        plain: true,
      });
      removeFile(item.id)
        .then((msg) => {
          loading?.close?.();
          messageIns?.success?.(msg);
          handleReloadData();
        })
        .catch((e) => {
          loading?.close?.();
          messageIns?.error?.(e.message);
        });
    })
    ?.catch?.(() => {});
};

/** 分组右键菜单项点击事件 */
const handleItemCommand = (command) => {
  if (ctxMenuFileItem == null) {
    return;
  }
  if (command === "rename") {
    openRenameItem(ctxMenuFileItem);
  } else if (command === "add") {
    openGroupAdd(ctxMenuFileItem);
  } else if (command === "remove") {
    removeItem(ctxMenuFileItem);
  }
};

/** 关闭请求加载图标 */
const hideLoading = () => {
  loading.value = false;
};

/** 打开请求加载图标 */
const showLoading = () => {
  loading.value = true;
};

/** 查询分组数据 */
const queryGroup = () => {
  showLoading();
  listFiles({ is_directory: 1 })
    .then((list) => {
      const result = [
        { id: -1, name: "全部" },
        { id: 0, name: "未分组" },
        ...toTree({
          data: list,
          idField: "id",
          parentIdField: "parent_id",
        }),
      ];
      groupData.value = result;
      const oldSelected =
        groupSelected.value == null
          ? void 0
          : findTree(result, (d) => d.id === groupSelected.value?.id);
      groupSelected.value = null;
      nextTick(() => {
        handleGroupSelect(oldSelected || result[0]);
      });
    })
    .catch((e) => {
      groupData.value = [];
      messageIns.error(e.message);
      hideLoading();
    });
};

/** 刷新文件数据 */
const queryData = (parent_id) => {
  showLoading();
  const params = parent_id == null ? void 0 : { page: 1, name: "", parent_id };
  fileListRef.value && fileListRef.value.queryData(params);
};

/** 清空文件选中 */
const clearSelections = () => {
  fileListRef.value && fileListRef.value.clearSelections();
};

/** 弹窗打开事件 */
const handleOpen = () => {
  clearSelections();
  queryGroup();
};

/** 弹窗关闭事件 */
const handleClose = () => {
  clearSelections();
  emit("close");
};

/** 取消按钮点击事件 */
const handleCancel = () => {
  visible.value = false;
};

/** 确定按钮点击事件 */
const handleConfirm = () => {
  showLoading();
  emit("done", fileListRef.value?.getSelections?.() || []);
};

defineExpose({ hideLoading });
</script>

<style lang="scss">
@use "./style/index.scss";
</style>
